/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mylhyl.zxing.scanner;


import com.mylhyl.zxing.scanner.camera.CameraManager;
import com.mylhyl.zxing.scanner.common.Scanner;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;

final class ViewfinderView extends Component implements Component.DrawTask {

    private static final int CURRENT_POINT_OPACITY = 0xA0;
    private final Paint paint;
    private CameraManager cameraManager;
    private PixelMap resultBitmap;

    private int animationDelay = 0;
    private PixelMap laserLineBitmap;

    private float laserLineTop;// 扫描线最顶端位置

    private int laserLineHeight;//扫描线默认高度
    private int frameCornerWidth;//扫描框4角宽
    private int frameCornerLength;//扫描框4角高
    private int tipTextSize;//提示文字大小
    private int tipTextMargin;//提示文字与扫描框距离
    private ScannerOptions scannerOptions;

    public ViewfinderView(Context context, AttrSet attrs) {
        super(context, attrs);
        paint = new Paint();
        addDrawTask(this::onDraw);
    }

    void setCameraManager(CameraManager cameraManager) {
        this.cameraManager = cameraManager;
    }

    void setScannerOptions(ScannerOptions scannerOptions) {
        this.scannerOptions = scannerOptions;
        laserLineHeight = dp2px(scannerOptions.getLaserLineHeight());
        frameCornerWidth = dp2px(scannerOptions.getFrameCornerWidth());
        frameCornerLength = dp2px(scannerOptions.getFrameCornerLength());

        tipTextSize = Scanner.sp2px(getContext(), scannerOptions.getTipTextSize());
        tipTextMargin = dp2px(scannerOptions.getTipTextToFrameMargin());
    }

    private int dp2px(int dp) {
        return Scanner.dp2px(getContext(), dp);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (cameraManager == null) {
            return;
        }
        RectFloat frame = cameraManager.getFramingRect();//取扫描框
        //取屏幕预览
//        Rect previewFrame = cameraManager.getFramingRectInPreview();
        RectFloat previewFrame = cameraManager.getFramingRectInPreview();
        if (frame == null || previewFrame == null) {
            return;
        }
        // 如果有二维码结果的Bitmap，在扫取景框内绘制不透明的result Bitmap
        if (resultBitmap != null) {
            paint.setAlpha(CURRENT_POINT_OPACITY);
            canvas.drawPixelMapHolderRect(new PixelMapHolder(resultBitmap), null, frame, paint);
        } else {
            if (!scannerOptions.isFrameHide())
                drawFrame(canvas, frame);//绘制扫描框
            if (!scannerOptions.isFrameCornerHide())
                drawFrameCorner(canvas, frame);//绘制扫描框4角
            drawText(canvas, frame);// 画扫描框下面的字

            //全屏移动扫描线
            if (scannerOptions.isLaserMoveFullScreen()) {
                moveLaserSpeedFullScreen(cameraManager.getScreenResolution());//计算全屏移动位置
                drawLaserLineFullScreen(canvas, cameraManager.getScreenResolution());//绘制全屏扫描线
            } else {
                drawLaserLine(canvas, frame);//绘制扫描框内扫描线
                moveLaserSpeed(frame);//计算扫描框内移动位置
            }
            if (scannerOptions.getViewfinderCallback() != null) {
                scannerOptions.getViewfinderCallback().onDraw(this, canvas, frame);
            }
        }
    }

    private void moveLaserSpeed(RectFloat frame) {
        //初始化扫描线起始点为扫描框顶部位置
        if (laserLineTop == 0) {
            laserLineTop = frame.top;
        }
        int laserMoveSpeed = scannerOptions.getLaserLineMoveSpeed();
        // 每次刷新界面，扫描线往下移动 LASER_VELOCITY
        laserLineTop += laserMoveSpeed;
        if (laserLineTop >= frame.bottom) {
            laserLineTop = frame.top;
        }
        if (animationDelay == 0) {
            animationDelay = (int) ((1.0f * 1000 * laserMoveSpeed) / (frame.bottom - frame.top));
        }
    }

    private void moveLaserSpeedFullScreen(Point point) {
        //初始化扫描线起始点为顶部位置
        int laserMoveSpeed = scannerOptions.getLaserLineMoveSpeed();
        // 每次刷新界面，扫描线往下移动 LASER_VELOCITY
        laserLineTop += laserMoveSpeed;
//        if (laserLineTop >= point.y) {
        if (laserLineTop >= point.getPointY()) {
            laserLineTop = 0;
        }
        if (animationDelay == 0) {
            animationDelay = (int) ((1.0f * 1000 * laserMoveSpeed) / point.getPointY());
        }
    }

    /**
     * 绘制提示文字
     *
     * @param canvas
     * @param frame
     */
    private void drawText(Canvas canvas, RectFloat frame) {
        Paint textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setStyle(Paint.Style.FILL_STYLE);
        textPaint.setColor(new Color(scannerOptions.getTipTextColor()));
        textPaint.setTextSize(tipTextSize);

        float x = frame.left;//文字开始位置
        //根据 drawTextGravityBottom 文字在扫描框上方还是上文，默认下方
        float y = !scannerOptions.isTipTextToFrameTop() ? frame.bottom + tipTextMargin
                : frame.top - tipTextMargin;

        canvas.save();
        canvas.translate(x, y);
        canvas.drawText(textPaint, scannerOptions.getTipText(), 0, 0);
        canvas.restore();
    }

    /**
     * 绘制扫描框4角
     *
     * @param canvas
     * @param frame
     */
    private void drawFrameCorner(Canvas canvas, RectFloat frame) {
        paint.setColor(new Color(scannerOptions.getFrameCornerColor()));
        paint.setStyle(Paint.Style.FILL_STYLE);
        if (scannerOptions.isFrameCornerInside()) {
            // 左上角，左
            canvas.drawRect(new RectFloat(frame.left, frame.top, frame.left + frameCornerWidth, frame.top + frameCornerLength), paint);
            // 左上角，上
            canvas.drawRect(new RectFloat(frame.left, frame.top, frame.left + frameCornerLength, frame.top + frameCornerWidth), paint);
            // 右上角，右
            canvas.drawRect(new RectFloat(frame.right - frameCornerWidth, frame.top, frame.right, frame.top + frameCornerLength),
                    paint);
            // 右上角，上
            canvas.drawRect(new RectFloat(frame.right - frameCornerLength, frame.top, frame.right, frame.top + frameCornerWidth),
                    paint);
            // 左下角，左
            canvas.drawRect(new RectFloat(frame.left, frame.bottom - frameCornerLength, frame.left + frameCornerWidth, frame.bottom)
                    , paint);
            // 左下角，下
            canvas.drawRect(new RectFloat(frame.left, frame.bottom - frameCornerWidth, frame.left + frameCornerLength, frame.bottom)
                    , paint);
            // 右下角，右
            canvas.drawRect(new RectFloat(frame.right - frameCornerWidth, frame.bottom - frameCornerLength, frame.right,
                    frame.bottom), paint);
            // 右下角，下
            canvas.drawRect(new RectFloat(frame.right - frameCornerLength, frame.bottom - frameCornerWidth, frame.right,
                    frame.bottom), paint);
        } else {
            // 左上角
            canvas.drawRect(new RectFloat(frame.left - frameCornerWidth, frame.top, frame.left, frame.top + frameCornerLength), paint);
            canvas.drawRect(new RectFloat(frame.left - frameCornerWidth, frame.top - frameCornerWidth,
                    frame.left + frameCornerLength, frame.top), paint);
            // 右上角
            canvas.drawRect(new RectFloat(frame.right, frame.top, frame.right + frameCornerWidth, frame.top + frameCornerLength),
                    paint);
            canvas.drawRect(new RectFloat(frame.right - frameCornerLength, frame.top - frameCornerWidth,
                    frame.right + frameCornerWidth, frame.top), paint);
            // 左下角
            canvas.drawRect(new RectFloat(frame.left - frameCornerWidth, frame.bottom - frameCornerLength, frame.left, frame.bottom)
                    , paint);
            canvas.drawRect(new RectFloat(frame.left - frameCornerWidth, frame.bottom, frame.left + frameCornerLength,
                    frame.bottom + frameCornerWidth), paint);
            // 右下角
            canvas.drawRect(new RectFloat(frame.right, frame.bottom - frameCornerLength, frame.right + frameCornerWidth,
                    frame.bottom), paint);
            canvas.drawRect(new RectFloat(frame.right - frameCornerLength, frame.bottom, frame.right + frameCornerWidth,
                    frame.bottom + frameCornerWidth), paint);
        }
    }

    /**
     * 画扫描框
     *
     * @param canvas
     * @param frame
     */
    private void drawFrame(Canvas canvas, RectFloat frame) {
        paint.setColor(new Color(scannerOptions.getFrameStrokeColor()));//扫描边框色
        paint.setStrokeWidth(scannerOptions.getFrameStrokeWidth());
        paint.setStyle(Paint.Style.STROKE_STYLE);
        canvas.drawRect(frame, paint);
    }

    /**
     * 画扫描线
     *
     * @param canvas
     * @param frame
     */
    private void drawLaserLine(Canvas canvas, RectFloat frame) {
        ScannerOptions.LaserStyle laserLineStyle = scannerOptions.getLaserStyle();
        if (laserLineStyle == ScannerOptions.LaserStyle.COLOR_LINE) {
            paint.setStyle(Paint.Style.FILL_STYLE);
            paint.setColor(new Color(scannerOptions.getLaserLineColor()));// 设置扫描线颜色
            canvas.drawRect(new RectFloat(frame.left, laserLineTop, frame.right, laserLineTop + laserLineHeight), paint);
            return;
        }
        // 图片资源文件转为 Bitmap
        if (laserLineBitmap == null) {
            if (laserLineStyle == ScannerOptions.LaserStyle.DRAWABLE_LINE ||
                    laserLineStyle == ScannerOptions.LaserStyle.DRAWABLE_GRID) {
                laserLineBitmap = Scanner.drawableToBitmap(scannerOptions.getLaserLineDrawable());
            } else {
            }
        }
        int height = laserLineBitmap.getImageInfo().size.height;//取原图高
        // 网格图片
        if (laserLineStyle == ScannerOptions.LaserStyle.RES_GRID ||
                laserLineStyle == ScannerOptions.LaserStyle.DRAWABLE_GRID) {
            RectFloat dstRectF = new RectFloat(frame.left, frame.top, frame.right, laserLineTop);
            RectFloat srcRect = new RectFloat(0, (int) (height - dstRectF.getHeight()), laserLineBitmap.getImageInfo().size.width, height);
            canvas.drawPixelMapHolderRect(new PixelMapHolder(laserLineBitmap), srcRect, dstRectF, paint);
            return;
        }
        // 线条图片，如果没有设置线条高度，则用图片原始高度
        if (laserLineHeight == dp2px(ScannerOptions.DEFAULT_LASER_LINE_HEIGHT)) {
            laserLineHeight = laserLineBitmap.getImageInfo().size.height / 2;
        }
        RectFloat laserRect = new RectFloat(frame.left, laserLineTop, frame.right, laserLineTop + laserLineHeight);
        canvas.drawPixelMapHolderRect(new PixelMapHolder(laserLineBitmap), null, laserRect, paint);
    }


    /**
     * 画全屏宽扫描线
     *
     * @param canvas
     * @param point
     */
    private void drawLaserLineFullScreen(Canvas canvas, Point point) {
        ScannerOptions.LaserStyle laserLineStyle = scannerOptions.getLaserStyle();
        if (laserLineStyle == ScannerOptions.LaserStyle.COLOR_LINE) {
            paint.setStyle(Paint.Style.FILL_STYLE);
            paint.setColor(new Color(scannerOptions.getLaserLineColor()));// 设置扫描线颜色
            canvas.drawRect(new RectFloat(0, laserLineTop, point.getPointX(), laserLineTop + laserLineHeight), paint);
            return;
        }
        // 图片资源文件转为 Bitmap
        if (laserLineBitmap == null) {
            if (laserLineStyle == ScannerOptions.LaserStyle.DRAWABLE_LINE ||
                    laserLineStyle == ScannerOptions.LaserStyle.DRAWABLE_GRID) {
                laserLineBitmap = Scanner.drawableToBitmap(scannerOptions.getLaserLineDrawable());
            } else {
            }
        }
        int height = laserLineBitmap.getImageInfo().size.height;//取原图高
        // 网格图片
        if (laserLineStyle == ScannerOptions.LaserStyle.RES_GRID ||
                laserLineStyle == ScannerOptions.LaserStyle.DRAWABLE_GRID) {
            float dstRectFTop = 0;
            if (laserLineTop >= height) {
                dstRectFTop = laserLineTop - height;
            }
            RectFloat dstRectF = new RectFloat(0, dstRectFTop, point.getPointX(), laserLineTop);
            RectFloat srcRect = new RectFloat(0, (int) (height - dstRectF.getHeight()), laserLineBitmap.getImageInfo().size.width, height);
            canvas.drawPixelMapHolderRect(new PixelMapHolder(laserLineBitmap), srcRect, dstRectF, paint);
            return;
        }
        // 线条图片， 如果没有设置线条高度，则用图片原始高度
        if (laserLineHeight == dp2px(ScannerOptions.DEFAULT_LASER_LINE_HEIGHT)) {
            laserLineHeight = laserLineBitmap.getImageInfo().size.height / 2;
        }
        RectFloat laserRect = new RectFloat(0, laserLineTop, point.getPointX(), laserLineTop + laserLineHeight);
        canvas.drawPixelMapHolderRect(new PixelMapHolder(laserLineBitmap), null, laserRect, paint);
    }

    void drawViewfinder() {
        PixelMap resultBitmap = this.resultBitmap;
        this.resultBitmap = null;
        if (resultBitmap != null) {
            resultBitmap.release();
        }
        invalidate();
    }

    void drawResultBitmap(PixelMap barcode) {
        resultBitmap = barcode;
        invalidate();
    }

    void laserLineBitmapRecycle() {
        if (laserLineBitmap != null) {
            laserLineBitmap.release();
            laserLineBitmap = null;
        }
    }
}
